#include "assgl.h"

#include <string>
#include <iostream>
#include <memory.h>
#include <opencv2/core/base.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc_c.h>
#include <opencv2/opencv.hpp>


#include "assglUtils.h"
#include "assglParser.h"
#include "assglConvertMid.h"
// #include "assglOpengl.h"

#include "glcontext.h"
#include "overlayobj.h"
#include "gltxt.h"
#include "textOverlay.h"


using namespace cv;

char *assglGetVersion()
{
	return "1.0.0";
}


//AVFrame 转 cv::mat
EXTERN_C cv::Mat avframeToCvmat(const AVFrame *frame)
{
    int width = frame->width;
    int height = frame->height;
    // cv::Mat image(height, width, CV_8UC3);
    cv::Mat image(height, width, CV_8UC4);
    int cvLinesizes[1];
    cvLinesizes[0] = image.step1();
    SwsContext *conversion = sws_getContext(width,
                                            height,
                                            (AVPixelFormat) frame->format,
                                            width,
                                            height,
                                            // AVPixelFormat::AV_PIX_FMT_BGR24,
                                            AVPixelFormat::AV_PIX_FMT_RGBA,
                                            SWS_FAST_BILINEAR,
                                            NULL,
                                            NULL,
                                            NULL);
    sws_scale(conversion, frame->data, frame->linesize, 0, height, &image.data, cvLinesizes);
    sws_freeContext(conversion);
    return image;
}

//cv::Mat 转 AVFrame
EXTERN_C AVFrame *cvmatToAvframe(cv::Mat *image, AVFrame *frame)
{
    int width = image->cols;
    int height = image->rows;
    int cvLinesizes[1];
    cvLinesizes[0] = image->step1();
    if (frame == NULL) {
        frame = av_frame_alloc();
        av_image_alloc(frame->data,
                       frame->linesize,
                       width,
                       height,
                       AVPixelFormat::AV_PIX_FMT_YUV420P,
                        // AVPixelFormat::AV_PIX_FMT_RGBA,
                       1);

        // 计算YUV420P格式所需的缓冲区大小  
        int numBytes = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, width, height, 1);  
        uint8_t* buffer = (uint8_t*)av_malloc(numBytes * sizeof(uint8_t));  
        if (!buffer) {  
            std::cerr << "Could not allocate image buffer!" << std::endl;  
            av_frame_free(&frame);  
            return nullptr;  
        }  
    
        // 填充AVFrame的data和linesize  
        av_image_fill_arrays(frame->data, frame->linesize, buffer, AV_PIX_FMT_YUV420P, width, height, 1);  
    
        // 设置frame的其他参数  
        frame->width = width;  
        frame->height = height;  
        frame->format = AV_PIX_FMT_YUV420P; 
    }
    std::cout << "frame->format:" << frame->format << std::endl;

    SwsContext *conversion = sws_getContext(width,
                                            height,
                                            AVPixelFormat::AV_PIX_FMT_BGR24,
                                            // AVPixelFormat::AV_PIX_FMT_RGB24,
                                            // AVPixelFormat::AV_PIX_FMT_RGBA,
                                            width,
                                            height,
                                            (AVPixelFormat) frame->format,
                                            SWS_FAST_BILINEAR,
                                            // SWS_BICUBIC,
                                            NULL,
                                            NULL,
                                            NULL);
    sws_scale(conversion, &image->data, cvLinesizes, 0, height, frame->data, frame->linesize);
    sws_freeContext(conversion);
    return frame;
}

/**
 * @brief 实现两个AVFrame数据的融合
 * 
 * @param foregroundFrame 
 * @param backgroundFrame 
 * @return AVFrame* 
 */
cv::Mat blendFromCV(const cv::Mat &src1, const cv::Mat &src2)
{
    int type1 = src1.type();
    int type2 = src2.type();
    std::cout << "type1:" <<  type1 << "--type2:" << type2 << "--CV_8UC4:" << CV_8UC4 << std::endl;
	// 确保两个图像具有相同的尺寸和类型（BGRA）  
    CV_Assert(src1.size() == src2.size() && src1.type() == CV_8UC4 && src2.type() == CV_8UC4);  
  
    cv::Mat dst = cv::Mat::zeros(src1.size(), src1.type());  
  
    for (int y = 0; y < src1.rows; ++y) {  
        for (int x = 0; x < src1.cols; ++x) {  
            cv::Vec4b& pixelDst = dst.at<cv::Vec4b>(y, x);  
            const cv::Vec4b& pixelSrc1 = src1.at<cv::Vec4b>(y, x);  
            const cv::Vec4b& pixelSrc2 = src2.at<cv::Vec4b>(y, x);  
  
            // 计算混合后的颜色值  
            // 使用简单的线性插值（alpha blending）  
            float alpha = pixelSrc1[3] / 255.0f;  // Alpha值在0-255之间，转换为0-1之间  
            float invAlpha = 1.0f - alpha;  
  
            pixelDst[0] = cv::saturate_cast<uchar>(pixelSrc1[0] * alpha + pixelSrc2[0] * invAlpha);  // Blue  
            pixelDst[1] = cv::saturate_cast<uchar>(pixelSrc1[1] * alpha + pixelSrc2[1] * invAlpha);  // Green  
            pixelDst[2] = cv::saturate_cast<uchar>(pixelSrc1[2] * alpha + pixelSrc2[2] * invAlpha);  // Red  
            pixelDst[3] = cv::saturate_cast<uchar>(255);  // Alpha通道设为完全不透明，或者你也可以根据需要进行混合  
        }  
    }  
  
    return dst;  
	// return cv::Mat();
}

cv::Mat convert8UC4to8UC3(const cv::Mat& src) {  
    // 确保输入图像是有效的且为CV_8UC4类型  
    if (src.empty() || src.type() != CV_8UC4) {  
        std::cerr << "Input image is empty or not of type CV_8UC4!" << std::endl;  
        return cv::Mat();  
    }  
  
    // 创建一个新的Mat对象，类型为CV_8UC3，尺寸为src的尺寸  
    cv::Mat dst;  
    dst.create(src.size(), CV_8UC3);  
  
    // 以下是直接复制的方式：  
    for (int y = 0; y < src.rows; ++y) {  
        for (int x = 0; x < src.cols; ++x) {  
            dst.at<cv::Vec3b>(y, x)[0] = src.at<cv::Vec4b>(y, x)[0]; // B  
            dst.at<cv::Vec3b>(y, x)[1] = src.at<cv::Vec4b>(y, x)[1]; // G  
            dst.at<cv::Vec3b>(y, x)[2] = src.at<cv::Vec4b>(y, x)[2]; // R  
        }  
    }  
    return dst;  
}  

EXTERN_C AssglLib *assgl_read_file(const char *assFilename)
{
	std::string remark;
	std::string txtData = ReadConfig(assFilename);
	if (txtData.empty()){
		LOGINFO("err:open file failed!!!");
		return nullptr;	
	}

	AssglLib *assglContext = (AssglLib *)calloc(1,sizeof(AssglLib));
	if (assglContext == nullptr){
		LOGINFO("err:calloc assglContext failed!!!");
		return nullptr;	
	}

	remark = parseTxtData(assglContext,txtData);
	if (!remark.empty()){
		LOGINFO("err:parseTxtData function failed:");
		std::cout << remark << std::endl;
		return nullptr;	
	}
	
	return assglContext;
}

void assglSetPixFmt(AssglLib *lib, int pixFmt)
{
	lib->PixFmt = pixFmt;
}

EXTERN_C void assgl_free(AssglLib *lib)
{
}

EXTERN_C void assglWindowInit(int width, int height,GlParam *glparam)
{
    /* 创建gl运行环境 */
    glparam->context = glcCreateGlContext(width,height); // 双击窗口退出
    /* 进入gl环境 */
    glcMakeCurrent(glparam->context);
    
    /* 初始化freetype 库 */
    init_ftlib();
    const char *defs[] = {"simsun.ttc"};//初始化一个默认字体（备用）库
    setDefFonts(defs,1); 

    glparam->obj = createTextOverlayObj(nullptr);  
    glparam->gltxt[FONTOBJCOUNTS] = 0;
    glparam->glTxtNum = -1;
}

// EXTERN_C void assglTextInit(int width, int height, GlParam *glparam)
// {
    
    
//     /* 创建一个overlay 对象 */
//     // POverlayobj obj = createTextOverlayObj(overlayeffect0);
//     glparam->obj = createTextOverlayObj(nullptr);
    
//     /* 初始化文字对象 */
//     glparam->gltxt = gltxtCreateOne();

//     // __setText_text(glparam->gltxt,"2004年5月 arabic:(هلأنت بخير)\n春江潮水连海平，\n海上明月共潮生。\n");
//     setTextFont(glparam,"2004年5月 arabic:(هلأنت بخير)\n春江潮水连海平，\n海上明月共潮生。\n");
//     __setText_color(glparam->gltxt,0xffffffff,0);
//     __setText_color(glparam->gltxt,0xff00ffff,1);
//     __setText_color(glparam->gltxt,0xff003333,2);
//     __setText_color(glparam->gltxt,0xffffffff,3);
//     __setText_color(glparam->gltxt,0xffff00ff,4);
//     __setText_color(glparam->gltxt,0xff33aaff,5);
//     __setText_outlineWidth(glparam->gltxt,0.1f,1);
//     __setText_light(glparam->gltxt,1);

//     __setText_align(glparam->gltxt,2); //  不支持垂直排版
//     __gltxtSetMargin(glparam->gltxt,30,100,30,100);
//     __setText_PercType(glparam->gltxt,3); // 开启字间动画
//     double dw = __setText_setWidth0f(glparam->gltxt, 400.f);  /* 注意： 要最后设置宽度，不然可能不准*/
// }


EXTERN_C char* assglReader(int width, int height, GlParam *glparam)
{
    // float durtion = 12.f;
    // int time = clock();// / CLOCKS_PER_SEC; 
    // float ftime = ((float) time)/ 1000.f; // ((float) CLOCKS_PER_SEC);
    // ftime = durtion * ( ftime / durtion - floor(ftime / durtion) );

    // /* 渲染文字到后台帧缓存 */    
    // gltxtDoAni(glparam->gltxt,ftime,durtion);
    // __getBufSize(glparam->gltxt,&(glparam->obj->sw),&(glparam->obj->sh));
    // glparam->obj->x = 50;
    // glparam->obj->y = 50;
    // glparam->obj->angle = 0.;
    // // glparam->obj->t = ftime;//time / 1000.f;
    // // glparam->obj->durtion = durtion;// dur / 1000.f;

    // /* 文字缓存overlay到窗口缓存 */
    // overlayText(glparam->context,glparam->gltxt,glparam->obj);

    char * buf = new char[height * width * 4];
    glcReadCurPixelsRGBA(glparam->context,buf,width,height);// 读取窗口缓存像素点
    return buf;
}

void savePictureFromCvMat(std::string filename,cv::Mat matDta){
    bool success = cv::imwrite(filename, matDta);
    if (!success) {  
        std::cout << "Error saving image to " << filename << std::endl;  
        
    }  
    return ;  
}

/**
 * @brief 
 * 
 * @param buffer 
 * @param buffer_size 
 * @param width 
 * @param height 
 * @param frame 
 */
EXTERN_C void charToAVFrame(char *buffer, int buffer_size, int width, int height, AVFrame **frame,enum AVPixelFormat pix_fmt)
{
    if ((*frame) == nullptr){
        (*frame) = av_frame_alloc();
    }

    if (buffer_size == 0){
        buffer_size = width * height * 4;
    }
    av_image_fill_arrays((*frame)->data, (*frame)->linesize, (uint8_t*)buffer, pix_fmt, width, height, 1);//AV_PIX_FMT_RGBA  
    (*frame)->width = width;
    (*frame)->height = height;
    (*frame)->format = pix_fmt;
}


char *assglReaderToChar(int width, int height, AssglLib *assglLib,double timeMs,bool *isDispose)
{
    //在这里进行业务逻辑判断
    char * buf = NULL;
    bool isNeedDraw = false;    //是否需要重新画
    bool isNeedMiditify = false; //该字段表示是否是一次修改都没有的情况,如果有修改，则为true，反之为false
    if (!(assglLib && assglLib->GlParamS.context)){
        std::cout << "assglLib or assglLib->GlParamS.context is NULL" << std::endl;
    }
    for(int i = 0;i < assglLib->AssglTrackCounts+1;i++){
        AssglTrack *trackEvent = assglLib->AssglTrackItem + i;
        if ((trackEvent->StartTime <= timeMs) && (timeMs < trackEvent->StartTime + trackEvent->Duration) ){  //确定轨道
            if( std::strlen(trackEvent->EffectStyle) == 0){
                if (!isNeedDraw){
                    isNeedDraw = true;
                    {
                        //补充业务逻辑
                        initFontObj(&(assglLib->GlParamS));
                        setTextFont(&(assglLib->GlParamS),"xxxx.ttf");
                    }
                }
            }
            else if(std::strlen(trackEvent->EffectStyle) > 0){
                isNeedDraw = true;
                {
                    // 补充业务逻辑
                }
            }
            isNeedMiditify = true;
        }else{
            //这里要判断轨道id
            isNeedDraw = true;
            {
                // 补充业务逻辑
            }
        }
    }

    if (isNeedMiditify){
        //生成buf
        if (isNeedDraw){
            if (!(assglLib->GlParamS.gltxt && assglLib->GlParamS.obj))
            {
                std::cout << "assglLib->GlParamS.gltxt orassglLib->GlParamS.obj is NULL" << std::endl;
            }
            buf = assglReader(width, height, &(assglLib->GlParamS));
            assglLib->PicBuff.Buffer = buf;
            assglLib->PicBuff.BufferSize = width* height*4;
        }
        else{
            buf = assglLib->PicBuff.Buffer;
        }
    }else{
        *isDispose = !isNeedMiditify;
    }
	return buf;
}

EXTERN_C AVFrame *blendFromCV(const AVFrame *foregroundFrame,const AVFrame *backgroundFrame, AVFrame *dstFrame)
{
	//AVFrameToMat
	cv::Mat foreground = avframeToCvmat(foregroundFrame);
    savePictureFromCvMat("huanyuan_foreground.jpg",foreground);

    cv::Mat background = avframeToCvmat(backgroundFrame);
    savePictureFromCvMat("huanyuan_background.png",background); 

	//blend
    cv::Mat blendPng = blendFromCV(foreground,background);
    savePictureFromCvMat("huanyuan_blendPng.jpg",blendPng); 
    std::cout << "blendPng type:" << blendPng.type() << std::endl;

    cv::Mat blendPngCU3 = convert8UC4to8UC3(blendPng);
    std::cout << "blendPngCU3 type:" << blendPngCU3.type() << std::endl;
	//MatToAVFrame
    AVFrame *frame = cvmatToAvframe(&blendPngCU3,dstFrame);

    return frame;
}


AVFrame *assglReaderToFrame(AssglLib *assglLib,double timeMs,AVFrame *picref,AVFrame *out)
{
    AVFrame *framePng = NULL;
    bool isDispose = false; //表示对数据帧进行了处理，如果没有进行处理，则该字段为true

    char * buf = assglReaderToChar(assglLib->PlayResX,assglLib->PlayResY,assglLib,timeMs,&isDispose);
    if (isDispose){
        out = picref;
        return out;
    }

    if (buf == NULL ){
        std::cerr << "output image buf is NULL" << std::endl;
    }

    charToAVFrame(buf,0,assglLib->PlayResX,assglLib->PlayResY,&framePng,AV_PIX_FMT_RGBA);
	
    out = blendFromCV(framePng,picref,out);
    if (out == NULL){
        std::cerr << "blend图片失败" << std::endl;
    }
    return out;
}